package com.macro.mall.portal.util;

import org.json.JSONObject;

import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.List;
import java.util.Random;
import java.util.UUID;

public class MyCodeUtil {

    /**
     * 描述:生成随机的六位验证码
     *
     * @return code
     */
    public static String getValidationCode() {
        String code = "";
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            code += random.nextInt(10);
        }
        return code;
    }

    /**
     * 获取UUID生成的32位字符串
     *
     * @return
     */
    public static String getIdCode() {
        return UUID32();
    }

    /**
     * @return 获取UUID生成的32位字符串
     */
    public static String UUID32() {
        String uuid36 = UUID.randomUUID().toString();
        String uuid32 = uuid36.replaceAll("-", "");
        return uuid32.toUpperCase();
    }

    /**
     * 通过md5进行加密
     *
     * @param source 要加密的数据
     * @return
     */
    public static String MD5Encryption(String source) {
        if (source == null) {
            source = "";
        }

        // 1.获取MessageDigest对象
        MessageDigest digest = null;
        try {
            digest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        // 2.执行加密操作
        byte[] bytes = source.getBytes();

        // 在MD5算法这，得到的目标字节数组的特点：长度固定为16
        byte[] targetBytes = digest.digest(bytes);

        // 3.声明字符数组
        char[] characters = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

        // 4.遍历targetBytes
        StringBuilder builder = new StringBuilder();
        for (byte b : targetBytes) {
            // 5.取出b的高四位的值
            // 先把高四位通过右移操作拽到低四位
            int high = (b >> 4) & 15;

            // 6.取出b的低四位的值
            int low = b & 15;

            // 7.以high为下标从characters中取出对应的十六进制字符
            char highChar = characters[high];

            // 8.以low为下标从characters中取出对应的十六进制字符
            char lowChar = characters[low];

            builder.append(highChar).append(lowChar);
        }

        return builder.toString();
    }

    /**
     * 逢一进一格式化数据
     *
     * @param source 待格式化数据
     * @param places 保留小数位数，null或小于0则默认保留两位小数
     * @return
     */
    public static double formateNumber1(Integer source, Integer places) {
        if (places == null || places < 0) {
            places = 2;
        }
        BigDecimal bigDecimal = new BigDecimal(source).setScale(places, BigDecimal.ROUND_UP);
        return bigDecimal.doubleValue();
    }

    /**
     * 获取由0-9，A-Z，a-z随机组成的字符串
     *
     * @param minLenth 指定字符串的最小长度
     * @param maxLenth 指定字符串的最大长度
     * @return
     */
    public static String getRandomStr(int minLenth, int maxLenth) {
        int lenth = randomInt(minLenth, maxLenth);

        StringBuffer result = new StringBuffer();
        for (int i = 0; i < lenth; i++) {
            int type = randomInt(1, 3);
            switch (type) {
                case 1:
                    result.append((char) randomInt('0', '9'));
                    break;

                case 2:
                    result.append((char) randomInt('A', 'Z'));
                    break;

                case 3:
                    result.append((char) randomInt('a', 'z'));
                    break;
            }
        }

        return result.toString();
    }

    /**
     * 获取指定范围内的一个随机数，包含指定的最小与最大值，注：最大值必须大于1
     *
     * @param min 随机数最小值
     * @param max 随机数最大值
     * @return
     */
    public static int randomInt(int min, int max) {
        Random random = new Random();
        return random.nextInt(max) % (max - min + 1) + min;
    }

    /**
     * 生成由随机数最小值minNum到随机数最大值maxNum随机组成的长度为length的随机数字字符串
     *
     * @param length 随机数字字符串的长度
     * @param minNum 随机数最小值
     * @param maxNum 随机数最大值
     * @return
     */
    public static String randomNumberStr(int length, int minNum, int maxNum) {
        minNum = Math.max(minNum, 0);
        maxNum = Math.min(maxNum, 9);

        StringBuilder randomNumberStr = new StringBuilder();
        for (int i = 0; i < length; i++) {
            randomNumberStr.append(randomInt(minNum, maxNum));
        }
        return randomNumberStr.toString();
    }

    /**
     * 生成指定由0-9随机数组成的指定长度为length的随机数字符串
     *
     * @param length 随机数字符串的长度
     * @return
     */
    public static String randomNumberStr(int length) {
        return randomNumberStr(length, 0, 9);
    }

    /**
     * 获取20位的订单号
     * 格式：YYYYMMDDHHmmss + 2位随机大写字母 + 4位随机数字
     *
     * @return
     */
    public static String getOrderNumber20() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

        String randomStr = "" + (char) randomInt('A', 'Z') + (char) randomInt('A', 'Z');

        String randomNum = "";
        for (int i = 0; i < 4; i++) {
            randomNum += randomInt(0, 9);
        }

        return timestamp + randomStr + randomNum;
    }

    /**
     * 获取23位的订单号
     * 格式：YYYYMMDDHHmmssSSS + 2位随机大写字母 + 4位随机数字
     *
     * @return
     */
    public static String getOrderNumber23() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));

        String randomStr = "" + (char) randomInt('A', 'Z') + (char) randomInt('A', 'Z');

        String randomNum = "";
        for (int i = 0; i < 4; i++) {
            randomNum += randomInt(0, 9);
        }

        return timestamp + randomStr + randomNum;
    }

    /**
     * 生成长度为6的字符串，格式：2位大写字母+4位随机数字
     *
     * @return
     */
    public static String randomStr6() {
        String randomStr = "" + (char) randomInt('A', 'Z') + (char) randomInt('A', 'Z');

        String randomNum = "";
        for (int i = 0; i < 4; i++) {
            randomNum += randomInt(0, 9);
        }
        return randomStr + randomNum;
    }

    /**
     * base64加密
     * @param source 待加密内容
     * @return
     */
    public static String base64Encrypt(String source) {
        return Base64.getEncoder().encodeToString(source.getBytes());
    }

    /**
     * base64解密
     * @param source 已加密内容
     * @return
     */
    public static String base64Decrypt(String source) {
        return new String(Base64.getDecoder().decode(source));
    }

    /**
     * 预设响应
     * {
     * "status": 状态码,
     * "message": 响应消息
     * "timestamp": 时间戳
     * "data": 响应数据
     * }
     *
     * @param status
     * @param message
     * @return
     */
    public static JSONObject responseCode(Integer status, String message, JSONObject data) {
        JSONObject res = new JSONObject();
        res.put("status", status);
        res.put("message", message);
        res.put("timestamp", MyDateTimeUtil.getDateFormat4());
        res.put("data", data);
        return res;
    }

    public static JSONObject responseCode() {
        return responseCode(200, "OK", null);
    }

    public static JSONObject responseCode(JSONObject data) {
        return responseCode(200, "OK", data);
    }

    public static JSONObject responseCode(JSONObject data, String message) {
        return responseCode(200, message, data);
    }

    public static JSONObject responseCode(String message) {
        return responseCode(200, message, null);
    }

    public static JSONObject responseCode(Integer status, String message) {
        return responseCode(status, message, null);
    }


    /**
     * 利用subList方法进行分页
     *
     * @param source 源list数据
     * @param page   页码，从1开始
     * @param size   条数，大于0
     * @return 分页后列表，超出列表或异常，返回null
     */
    public static List pageBySubList(List source, int page, int size) {
        int totalCount = source.size();
        int pageCount = 0;
        List subList;
        int m = totalCount % size;
        if (m > 0) {
            pageCount = totalCount / size + 1;
        } else {
            pageCount = totalCount / size;
        }
        try {
            if (m == 0) {
                subList = source.subList((page - 1) * size, size * (page));
            } else {
                if (page == pageCount) {
                    subList = source.subList((page - 1) * size, totalCount);
                } else {
                    subList = source.subList((page - 1) * size, size * (page));
                }
            }
        } catch (Exception e) {
            subList = null;
        }
        return subList;
    }
}
